package net.pws.oos.security;

import java.text.MessageFormat;
import java.util.List;
import java.util.Map;

import net.pws.common.beanutils.BeanUtils;
import net.pws.common.persistence.EntityManager;
import net.pws.common.security.spi.AuthenticateFailedException;
import net.pws.common.security.spi.AuthenticateProvider;
import net.pws.common.security.spi.DefaultPrincipal;
import net.pws.common.security.spi.PasswordEncoder;
import net.pws.common.security.spi.Principal;
import net.pws.common.util.StringUtils;
import net.pws.oos.biz.model.Organization;
import net.pws.oos.biz.model.Role;
import net.pws.oos.biz.model.User;
import net.pws.oos.web.dto.UserDto;

import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

@SuppressWarnings({ "rawtypes", "unchecked" })
public class CmsAuthenticateProvider implements AuthenticateProvider {
	
	protected Log logger = LogFactory.getLog(getClass());

	private static String getBindedRoleListSql = "select r.* from s_role r where r.id in (select ur.role_id from s_user_role ur where ur.user_id = ?) order by r.id ";

	private EntityManager entityManager;
	
	private PasswordEncoder passwordEncoder;

	public EntityManager getEntityManager() {
		return entityManager;
	}

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

	public PasswordEncoder getPasswordEncoder() {
		return passwordEncoder;
	}

	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

	public Principal authenticate(String username, String password) {
		if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
			throw new AuthenticateFailedException("无效的用户名！");
		}
		DefaultPrincipal result = new DefaultPrincipal();
		UserDto user = null;
		Map map = findUser4Authenticate(username);
		if (map != null) {
			user = new UserDto();
			BeanUtils.copyProperties(user, map);
			if (!User.isEnabled(user)) {
				throw new AuthenticateFailedException("用户被禁用，不能登录系统！");
			}

			logger.debug(MessageFormat.format("The user name:{0}", username));
			String encodedPassword = encodePassword(password);
			logger.debug(MessageFormat.format("The user provided password:{0}",
					encodedPassword));
			logger.debug(MessageFormat.format("The user owned password:{0}",
					user.getPassword()));
			if (StringUtils.isEmpty(user.getPassword())) {
				throw new AuthenticateFailedException("用户密码被禁用！");
			}
			if (!user.getPassword().equals(encodedPassword)) {
				throw new AuthenticateFailedException("密码错误！");
			}
			user.setPassword("********");
			result.setId(user.getId());
			result.setName(user.getName());
			result.setGroupCode(user.getOrganId());
			result.setPrivileged(BooleanUtils.isTrue(user.getPrivileged()));
			result.setWebAccessAllowed(BooleanUtils.isTrue(user
					.getWebAccessAllowed()));
			result.setMobileAccessAllowed(BooleanUtils.isTrue(user
					.getMobileAccessAllowed()));
			result.setRoles(findRoles(user.getId()));
			result.setDetail(user);
		}
		return result;
	}

	public String getValidInnerCode(Organization organ) {
		return organ.getInnerCode().substring(0, 5 * organ.getDepth());
	}

	private Map findUser4Authenticate(String account) {
		Map result = (Map) entityManager
				.findFirst(
						"select new map(u.id as id ,u.name as name,u.account as account,u.password as password,u.enabled as enabled,o.id as organId,u.privileged as privileged,u.webAccessAllowed as webAccessAllowed,u.mobileAccessAllowed as mobileAccessAllowed) from User u left join u.organization o where u.account=? or u.mobile=?",
						new Object[] { account, account });
		// if (result == null) {
		// result = (Map) entityManager
		// .findFirst(
		// "select new map(u.id as id ,u.name as name,u.account as account,u.password as password,u.enabled as enabled,o.id as organId,u.privileged as privileged,u.webAccessAllowed as webAccessAllowed,u.mobileAccessAllowed as mobileAccessAllowed) from User u left join u.organization o where u.mobile=?",
		// new Object[] { account });
		// }
		return result;
	}

	private Role[] findRoles(String userId) {
		List<Map> roleMaps = entityManager.nativeFindList(getBindedRoleListSql,
				new Object[] { userId });
		if (roleMaps == null || roleMaps.isEmpty()) {
			return new Role[0];
		}

		Role[] roles = new Role[roleMaps.size()];
		for (int i = 0; i < roles.length; i++) {
			Role role = new Role();
			Map map = roleMaps.get(i);
			BeanUtils.copyProperties(role, map);
			roles[i] = role;
		}
		return roles;
	}
	
	private String encodePassword(String password) {
		if(passwordEncoder == null) {
			return password;
		}
		return passwordEncoder.encode(password);
	}

}
